home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / msdos / lynx / source / www / library / implemen / htwais.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-25  |  23.3 KB  |  857 lines

  1. /*    WorldWideWeb - Wide Area Informaion Server Access    HTWAIS.c
  2. **    ==================================================
  3. **
  4. **    This module allows a WWW server or client to read data from a
  5. **    remote  WAIS
  6. **  server, and provide that data to a WWW client in hypertext form.
  7. **  Source files, once retrieved, are stored and used to provide
  8. **  information about the index when that is acessed.
  9. **
  10. ** Authors
  11. **    BK    Brewster Kahle, Thinking Machines, <Brewster@think.com>
  12. **    TBL    Tim Berners-Lee, CERN <timbl@info.cern.ch>
  13. **
  14. ** History
  15. **       Sep 91    TBL adapted shell-ui.c (BK) with HTRetrieve.c from WWW.
  16. **       Feb 91    TBL Generated HTML cleaned up a bit (quotes, escaping)
  17. **                Refers to lists of sources. 
  18. **       Mar 93    TBL   Lib 2.0 compatible module made.    
  19. **
  20. ** Bugs
  21. **    Uses C stream i/o to read and write sockets, which won't work
  22. **    on VMS TCP systems.
  23. **
  24. **    Should cache connections.
  25. **
  26. **    ANSI C only as written
  27. **
  28. ** Bugs fixed
  29. **      NT Nathan Torkington (Nathan.Torkington@vuw.ac.nz)
  30. **
  31. ** WAIS comments:
  32. **
  33. **    1.    Separate directories for different system's .o would help
  34. **    2.    Document ids are rather long!
  35. **
  36. ** WWW Address mapping convention:
  37. **
  38. **    /servername/database/type/length/document-id
  39. **
  40. **    /servername/database?word+word+word
  41. */
  42. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  43.    No guarantees or restrictions.  See the readme file for the full standard
  44.    disclaimer.
  45.  
  46.    Brewster@think.com
  47. */
  48.  
  49.  
  50. #define DIRECTORY "/cnidr.org:210/directory-of-servers"
  51. /* define DIRECTORY "/quake.think.com:210/directory-of-servers" */
  52.  
  53. #define BIG 1024    /* identifier size limit  @@@@@ */
  54.  
  55. /*            From WAIS
  56. **            ---------
  57. */
  58.  
  59. #include <ui.h>
  60.  
  61. #define MAX_MESSAGE_LEN 100000
  62. #define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
  63.  
  64. #define WAISSEARCH_DATE "Fri Jul 19 1991"
  65.  
  66.  
  67. /*            FROM WWW
  68. **            --------
  69. */
  70. #define BUFFER_SIZE 4096    /* Arbitrary size for efficiency */
  71.  
  72. #define HEX_ESCAPE '%'
  73.  
  74. #include "HTUtils.h"
  75. #include "tcp.h"
  76. #include "HTParse.h"
  77. #include "HTAccess.h"        /* We implement a protocol */
  78. #include "HTML.h"        /* The object we will generate */
  79.  
  80. /* #include "ParseWSRC.h" */
  81.  
  82. extern int WWW_TraceFlag;    /* Control diagnostic output */
  83. extern FILE * logfile;        /* Log file output */
  84.  
  85. PRIVATE BOOL    as_gate;    /* Client is using us as gateway */
  86.  
  87. PRIVATE char    line[2048];    /* For building strings to display */
  88.                 /* Must be able to take id */
  89.  
  90.  
  91. #include "HTParse.h"
  92. #include "HTFormat.h"
  93. #include "HTTCP.h"
  94. /* #include "HTWSRC.h"    */    /* Need some bits from here */
  95.  
  96. /*        Hypertext object building machinery
  97. */
  98. #include "HTML.h"
  99.  
  100. #define PUTC(c) (*target->isa->put_character)(target, c)
  101. #define PUTS(s) (*target->isa->put_string)(target, s)
  102. #define START(e) (*target->isa->start_element)(target, e, 0, 0)
  103. #define END(e) (*target->isa->end_element)(target, e)
  104. #define FREE_TARGET (*target->isa->free)(target)
  105.  
  106. struct _HTStructured {
  107.     CONST HTStructuredClass *    isa;
  108.     /* ... */
  109. };
  110.  
  111. struct _HTStream {
  112.     CONST HTStreamClass *    isa;
  113.     /* ... */
  114. };
  115.  
  116.  
  117. /*                                showDiags
  118. */
  119. /* modified from Jonny G's version in ui/question.c */
  120.  
  121. void showDiags ARGS2(
  122.     HTStream *,         target,
  123.     diagnosticRecord **,     d)
  124. {
  125.   long i;
  126.  
  127.   for (i = 0; d[i] != NULL; i++) {
  128.     if (d[i]->ADDINFO != NULL) {
  129.       PUTS("Diagnostic code is ");
  130.       PUTS(d[i]->DIAG);
  131.       PUTC(' ');
  132.       PUTS(d[i]->ADDINFO);
  133.       PUTC('\n'); ;
  134.     }
  135.   }
  136. }
  137.  
  138. /*    Matrix of allowed characters in filenames
  139. **    -----------------------------------------
  140. */
  141.  
  142. PRIVATE BOOL acceptable[256];
  143. PRIVATE BOOL acceptable_inited = NO;
  144.  
  145. PRIVATE void init_acceptable NOARGS
  146. {
  147.     unsigned int i;
  148.     char * good = 
  149.       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_$";
  150.     for(i=0; i<256; i++) acceptable[i] = NO;
  151.     for(;*good; good++) acceptable[(unsigned int)*good] = YES;
  152.     acceptable_inited = YES;
  153. }
  154.  
  155. /*    Transform file identifier into WWW address
  156. **    ------------------------------------------
  157. **
  158. **
  159. ** On exit,
  160. **    returns        nil if error
  161. **            pointer to malloced string (must be freed) if ok
  162. */
  163. char * WWW_from_archie ARGS1 (char *, file)
  164. {
  165.     char * end;
  166.     char * result;
  167.     char * colon;
  168.     for(end=file; *end > ' '; end++);    /* assumes ASCII encoding*/
  169.     result = (char *)malloc(10 + (end-file));
  170.     if (!result) return result;        /* Malloc error */
  171.     strcpy(result, "file://");
  172.     strncat(result, file, end-file);
  173.     colon = strchr(result+7, ':');    /* Expect colon after host */
  174.     if (colon) {
  175.     for(; colon[0]; colon[0]=colon[1], colon++);    /* move down */
  176.     }
  177.     return result;
  178. } /* WWW_from_archie */
  179.  
  180. /*    Transform document identifier into URL
  181. **    --------------------------------------
  182. **
  183. ** Bugs: A static buffer of finite size is used!
  184. **    The format of the docid MUST be good!
  185. **
  186. ** On exit,
  187. **    returns        nil if error
  188. **            pointer to malloced string (must be freed) if ok
  189. */
  190. PRIVATE char hex [17] = "0123456789ABCDEF";
  191. extern char from_hex PARAMS((char a));            /* In HTWSRC @@ */
  192.  
  193. PRIVATE char * WWW_from_WAIS ARGS1(any *, docid)
  194.  
  195. {
  196.     static char buf[BIG];
  197.     char * q = buf;
  198.     char * p = (docid->bytes);
  199.     int i, l;
  200.     if (TRACE) {
  201.     char *p;
  202.     fprintf(stderr, "WAIS id (%d bytes) is ", (int)docid->size);
  203.     for(p=docid->bytes; p<docid->bytes+docid->size; p++) {
  204.         if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */
  205.         fprintf(stderr, "%c", *p);
  206.         else
  207.         fprintf(stderr, "<%x>", (unsigned)*p);
  208.     }
  209.     fprintf(stderr, "\n");
  210.     }     
  211.     for (p=docid->bytes; (p<docid->bytes+docid->size) && (q<&buf[BIG]);) {
  212.     if (TRACE) fprintf(stderr, "    Record type %d, length %d\n",
  213.         p[0], p[1]);
  214.         if (*p>10) {
  215.         fprintf(stderr, "Eh? DOCID record type of %d!\n", *p);
  216.         return 0;
  217.     }
  218.     {    /* Bug fix -- allow any byte value 15 Apr 93 */
  219.         unsigned int i = (unsigned) *p++;
  220.         
  221.         if (i > 99) {
  222.         *q++ = (i/100) + '0';
  223.         i = i % 100;
  224.         }
  225.         if (i > 9) {
  226.         *q++ = (i/10) + '0';
  227.         i = i % 10;
  228.         }
  229.         *q++ = i + '0';    /* Record type */
  230.     }
  231.     *q++ = '=';        /* Separate */
  232.     l = *p++;        /* Length */
  233.     for(i=0; i<l; i++, p++){
  234.         if (!acceptable[*p]) {
  235.         *q++ = HEX_ESCAPE;    /* Means hex commming */
  236.         *q++ = hex[(*p) >> 4];
  237.         *q++ = hex[(*p) & 15];
  238.         }
  239.         else *q++ = *p;
  240.     }
  241.     *q++= ';';        /* Terminate field */
  242.     }
  243.     *q++ = 0;            /* Terminate string */
  244.     if (TRACE) fprintf(stderr, "WWW form of id: %s\n", buf); 
  245.     {
  246.         char * result = (char *)malloc(strlen(buf)+1);
  247.     strcpy(result, buf);
  248.     return result;
  249.     }
  250. } /* WWW_from_WAIS */
  251.  
  252.  
  253. /*    Transform URL into WAIS document identifier
  254. **    -------------------------------------------
  255. **
  256. ** On entry,
  257. **    docname        points to valid name produced originally by
  258. **            WWW_from_WAIS
  259. ** On exit,
  260. **    docid->size    is valid
  261. **    docid->bytes    is malloced and must later be freed.
  262. */
  263. PRIVATE any * WAIS_from_WWW ARGS2 (any *, docid, char *, docname)
  264. {
  265.     char *z;     /* Output pointer */
  266.     char *sor;    /* Start of record - points to size field. */
  267.     char *p;     /* Input pointer */
  268.     char *q;     /* Poisition of "=" */
  269.     char *s;     /* Position of semicolon */
  270.     int n;    /* size */
  271.     if (TRACE) fprintf(stderr, "WWW id (to become WAIS id): %s\n", docname); 
  272.     for(n=0, p = docname; *p; p++) {    /* Count sizes of strings */
  273.         n++;
  274.     if (*p == ';')  n--;        /* Not converted */
  275.     else if (*p == HEX_ESCAPE) n=n-2;    /* Save two bytes */
  276.         docid->size = n;
  277.     }
  278.     
  279.     docid->bytes = (char *) malloc(docid->size); /* result record */
  280.     z = docid->bytes;
  281.     
  282.     for(p = docname; *p; ) {    /* Convert of strings */
  283.                     /* Record type */
  284.                 
  285.     *z = 0;            /* Initialize record type */
  286.     while (*p >= '0' && *p <= '9') {
  287.         *z = *z*10 + (*p++ - '0');    /* Decode decimal record type */
  288.     }
  289.     z++;
  290.     if (*p != '=') return 0;
  291.     q = p;
  292.     
  293. /*        *z++ = *p++ - '0';
  294.     q = strchr(p , '=');
  295.     if (!q) return 0;
  296. */
  297.     s = strchr(q, ';');    /* (Check only) */
  298.     if (!s) return 0;    /* Bad! No ';';    */
  299.         sor = z;        /* Remember where the size field was */
  300.     z++;            /* Skip record size for now    */
  301.     for(p=q+1; *p!=';' ; ) {
  302.        if (*p == HEX_ESCAPE) {
  303.             char c;
  304.         unsigned int b;
  305.         p++;
  306.             c = *p++;
  307.         b =   from_hex(c);
  308.         c = *p++;
  309.         if (!c) break;    /* Odd number of chars! */
  310.         *z++ = (b<<4) + from_hex(c);
  311.         } else {
  312.             *z++ = *p++;    /* Record */
  313.         }
  314.     }
  315.     *sor = (z-sor-1);    /* Fill in size -- not counting size itself */
  316.     p++;            /* After semicolon: start of next record */
  317.     }
  318.     
  319.     if (TRACE) {
  320.     char *p;
  321.     fprintf(stderr, "WAIS id (%d bytes) is ", (int)docid->size);
  322.     for(p=docid->bytes; p<docid->bytes+docid->size; p++) {
  323.         if ((*p >= ' ') && (*p<= '~')) /* Assume ASCII! */
  324.         fprintf(stderr, "%c", *p);
  325.         else
  326.         fprintf(stderr, "<%x>", (unsigned)*p);
  327.     }
  328.     fprintf(stderr, "\n");
  329.     }     
  330.     return docid;        /* Ok */
  331.     
  332. } /* WAIS_from_WWW */
  333.  
  334.  
  335. /*    Send a plain text record to the client        output_text_record()
  336. **    --------------------------------------
  337. */
  338.  
  339. PRIVATE void output_text_record ARGS4(
  340.     HTStream *,            target,
  341.     WAISDocumentText *,        record,
  342.     boolean,            quote_string_quotes,
  343.     boolean,                    binary)
  344. {
  345.   long count;
  346.   /* printf(" Text\n");
  347.      print_any("     DocumentID:  ", record->DocumentID);
  348.      printf("     VersionNumber:  %d\n", record->VersionNumber);
  349.      */
  350.  
  351.   if (binary) {
  352.     (*target->isa->put_block)(target,
  353.                   record->DocumentText->bytes,
  354.                   record->DocumentText->size);
  355.     return;
  356.   }
  357.  
  358.   for(count = 0; count < record->DocumentText->size; count++){
  359.     long ch = (unsigned char)record->DocumentText->bytes[count];
  360.     if (ch == 27) {    /* What is this in for? Tim */
  361.  
  362.         /* then we have an escape code */
  363.         /* if the next letter is '(' or ')', then ignore two letters */
  364.         if('(' == record->DocumentText->bytes[count + 1] ||
  365.         ')' == record->DocumentText->bytes[count + 1])
  366.         count += 1;             /* it is a term marker */
  367.         else count += 4;        /* it is a paragraph marker */
  368.     } else if (ch == '\n' || ch == '\r') {
  369.         PUTC('\n');
  370.     } else if ((ch=='\t') || isprint(ch)){
  371.         PUTC(ch);
  372.     } 
  373.   }
  374. } /* output text record */
  375.  
  376.  
  377.  
  378. /*    Format A Search response for the client        display_search_response
  379. **    ---------------------------------------
  380. */
  381. /* modified from tracy shen's version in wutil.c
  382.  * displays either a text record or a set of headlines.
  383.  */
  384. void
  385. display_search_response ARGS4(
  386.     HTStructured *,        target,
  387.     SearchResponseAPDU *,    response,
  388.     char *,            database,
  389.     char *,             keywords)
  390. {
  391.   WAISSearchResponse  *info;
  392.   long i, k;
  393.   
  394.   BOOL archie =  strstr(database, "archie")!=0;    /* Specical handling */
  395.   
  396.   if (TRACE) fprintf(stderr, "HTWAIS: Displaying search response\n");
  397.   sprintf(line,
  398.       "Index %s contains the following %d item%s relevant to '%s'.\n",
  399.      database,
  400.      (int)(response->NumberOfRecordsReturned),
  401.      response->NumberOfRecordsReturned ==1 ? "" : "s",
  402.      keywords);
  403.  
  404.   PUTS(line);
  405.   PUTS("The first figure for each entry is its relative score, ");
  406.   PUTS("the second the number of lines in the item.");
  407.   START(HTML_MENU);
  408.  
  409.   if ( response->DatabaseDiagnosticRecords != 0 ) {
  410.     info = (WAISSearchResponse *)response->DatabaseDiagnosticRecords;
  411.     i =0; 
  412.  
  413.     if (info->Diagnostics != NULL)
  414.       showDiags((HTStream*)target, info->Diagnostics);
  415.  
  416.     if ( info->DocHeaders != 0 ) {
  417.       for (k=0; info->DocHeaders[k] != 0; k++ ) {
  418.     WAISDocumentHeader* head = info->DocHeaders[k];
  419.     char * headline = trim_junk(head->Headline);
  420.     any * docid = head->DocumentID;
  421.     char * docname;            /* printable version of docid */
  422.     i++;
  423.  
  424. /*    Make a printable string out of the document id.
  425. */
  426.     if (TRACE) fprintf(stderr, 
  427.         "HTWAIS:  %2ld: Score: %4ld, lines:%4ld '%s'\n", 
  428.            i,
  429.            (long int)(info->DocHeaders[k]->Score),
  430.            (long int)(info->DocHeaders[k]->Lines),
  431.            headline);
  432.  
  433.     START(HTML_LI);
  434.     sprintf(line, "%4ld  %4ld  ",
  435.         head->Score,
  436.         head->Lines);
  437.     PUTS( line);
  438.  
  439.     if (archie) {
  440.         char * www_name = WWW_from_archie(headline);
  441.         if (www_name) {
  442.         HTStartAnchor(target, NULL, www_name);
  443.         PUTS(headline);
  444.         
  445.         END(HTML_A);
  446.         free(www_name);
  447.         } else {
  448.          PUTS(headline);
  449.          PUTS(" (bad file name)");
  450.         }
  451.     } else { /* Not archie */
  452.         docname =  WWW_from_WAIS(docid);
  453.         if (docname) {
  454.         char * dbname = HTEscape(database, URL_XPALPHAS);
  455.         sprintf(line, "%s/%s/%d/%s",        /* W3 address */
  456.                     dbname,
  457.             head->Types ? head->Types[0] : "TEXT",
  458.             (int)(head->DocumentLength),
  459.             docname);
  460.         HTStartAnchor(target, NULL, ( (head->Types) 
  461.               && (!strcmp(head->Types[0], "URL"))) ? 
  462.                   headline : line); /* NT, Sep 93 */
  463.         PUTS(headline);
  464.         END(HTML_A);
  465.         free(dbname);
  466.         free(docname);
  467.         } else {
  468.          PUTS("(bad doc id)");
  469.         }
  470.       }
  471.       } /* next document header */
  472.     } /* if there were any document headers */
  473.     
  474.     if ( info->ShortHeaders != 0 ) {
  475.       k =0;
  476.       while (info->ShortHeaders[k] != 0 ) {
  477.     i++;
  478.     PUTS( "(Short Header record, can't display)");
  479.       }
  480.     }
  481.     if ( info->LongHeaders != 0 ) {
  482.       k =0;
  483.       while (info->LongHeaders[k] != 0) {
  484.     i++;
  485.     PUTS( "\nLong Header record, can't display\n");
  486.       }
  487.     }
  488.     if ( info->Text != 0 ) {
  489.       k =0;
  490.       while (info->Text[k] != 0) {
  491.     i++;
  492.     PUTS( "\nText record\n");
  493.     output_text_record((HTStream*)target, info->Text[k++], false, false);
  494.       }
  495.     }
  496.     if ( info->Headlines != 0 ) {
  497.       k =0;
  498.       while (info->Headlines[k] != 0) {
  499.     i++;
  500.     PUTS( "\nHeadline record, can't display\n");
  501.     /* dsply_headline_record( info->Headlines[k++]); */
  502.       }
  503.     }
  504.     if ( info->Codes != 0 ) {
  505.       k =0;
  506.       while (info->Codes[k] != 0) {
  507.     i++;
  508.     PUTS( "\nCode record, can't display\n");
  509.     /* dsply_code_record( info->Codes[k++]); */
  510.       }
  511.     }
  512.   }                /* Loop: display user info */
  513.   END(HTML_MENU);
  514.   PUTC('\n'); ;
  515. }
  516.  
  517.  
  518.  
  519.  
  520. /*        Load by name                    HTLoadWAIS
  521. **        ============
  522. **
  523. **    This renders any object or search as required
  524. */
  525. PUBLIC int HTLoadWAIS ARGS4(
  526.     CONST char *,        arg,
  527.     HTParentAnchor *,    anAnchor,
  528.     HTFormat,        format_out,
  529.     HTStream*,        sink)
  530.  
  531. #define MAX_KEYWORDS_LENGTH 1000
  532. #define MAX_SERVER_LENGTH 1000
  533. #define MAX_DATABASE_LENGTH 1000
  534. #define MAX_SERVICE_LENGTH 1000
  535. #define MAXDOCS 40
  536.  
  537. {
  538.     static CONST char * error_header =
  539. "<h1>Access error</h1>\nThe following error occured in accesing a WAIS server:<P>\n";
  540.     char * key;              /* pointer to keywords in URL */
  541.     char* request_message = NULL; /* arbitrary message limit */
  542.     char* response_message = NULL; /* arbitrary message limit */
  543.     long request_buffer_length;    /* how of the request is left */
  544.     SearchResponseAPDU  *retrieval_response = 0;
  545.     char keywords[MAX_KEYWORDS_LENGTH + 1];
  546.     char *server_name;    
  547.     char *wais_database = NULL;        /* name of current database */
  548.     char *www_database;            /* Same name escaped */
  549.     char *service;
  550.     char *doctype;
  551.     char *doclength;
  552.     long document_length;
  553.     char *docname;
  554.     FILE *connection = 0;
  555.     char * names;        /* Copy of arg to be hacked up */
  556.     BOOL ok = NO;
  557.     
  558.     extern FILE * connect_to_server();
  559.     
  560.     if (!acceptable_inited) init_acceptable();
  561.     
  562.         
  563. /*    Decipher and check syntax of WWW address:
  564. **    ----------------------------------------
  565. **
  566. **    First we remove the "wais:" if it was spcified.  920110
  567. */  
  568.     names = HTParse(arg, "", PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION);
  569.     key = strchr(names, '?');
  570.     
  571.     if (key) {
  572.         char * p;
  573.     *key++ = 0;    /* Split off keywords */
  574.     for (p=key; *p; p++) if (*p == '+') *p = ' ';
  575.     HTUnEscape(key);
  576.     }
  577.     if (names[0]== '/') {
  578.     server_name = names+1;
  579.     if (as_gate =(*server_name == '/'))
  580.         server_name++;    /* Accept one or two */
  581.     www_database = strchr(server_name,'/');
  582.     if (www_database) {
  583.         *www_database++ = 0;        /* Separate database name */
  584.         doctype = strchr(www_database, '/');
  585.         if (key) ok = YES;    /* Don't need doc details */
  586.         else if (doctype) {    /* If not search parse doc details */
  587.         *doctype++ = 0;    /* Separate rest of doc address */
  588.         doclength = strchr(doctype, '/');
  589.         if(doclength) {
  590.             *doclength++ = 0;
  591.             document_length = atol(doclength);
  592.             if (document_length) {
  593.             docname=strchr(doclength, '/');
  594.             if (docname) {
  595.                 *docname++ = 0;
  596.                 ok = YES;    /* To avoid a goto! */
  597.             } /* if docname */
  598.             } /* if document_length valid */
  599.         } /* if doclength */
  600.         } else { /* no doctype?  Assume index required */
  601.             if (!key) key = "";
  602.         ok = YES;
  603.         } /* if doctype */
  604.     } /* if database */
  605.      }
  606.      
  607.      if (!ok)
  608.      return HTLoadError(sink, 500, "Syntax error in WAIS URL");
  609.  
  610.      if (TRACE) fprintf(stderr, "HTWAIS: Parsed OK\n");
  611.      
  612.      service = strchr(names, ':');
  613.      if (service)  *service++ = 0;
  614.      else service = "210";
  615.      
  616.      if (server_name[0] == 0)
  617.         connection = NULL;
  618.  
  619.      else if (!(key && !*key))
  620.       if ((connection=connect_to_server(server_name,atoi(service)))
  621.            == NULL)  {
  622.      if (TRACE) fprintf (stderr,
  623.          "%sCan't open connection to %s via service %s.\n",
  624.          error_header, server_name, service);
  625.      free(names);
  626.      return HTLoadError(sink, 500, "Can't open connection to WAIS server");
  627.     }
  628.  
  629.     StrAllocCopy(wais_database,www_database);
  630.     HTUnEscape(wais_database);
  631.     
  632.     /* This below fixed size stuff is terrible */
  633.     request_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  634.     response_message = (char*)s_malloc((size_t)MAX_MESSAGE_LEN * sizeof(char));
  635.  
  636. /*    If keyword search is performed but there are no keywords,
  637. **    the user has followed a link to the index itself. It would be
  638. **    appropriate at this point to send him the .SRC file - how?
  639. */
  640.  
  641.     if (key && !*key) {                /* I N D E X */
  642.     
  643. #ifdef CACHE_FILE_PREFIX
  644.     char filename[256];
  645.     FILE * fp;
  646. #endif
  647.     HTStructured * target = HTML_new(anAnchor, format_out, sink);
  648.     
  649.     START(HTML_ISINDEX);
  650.  
  651.     {
  652.         START(HTML_TITLE);
  653.         PUTS(wais_database);
  654.         PUTS(" index");
  655.         END(HTML_TITLE);
  656.         
  657.         START(HTML_H1);
  658.         PUTS(wais_database);
  659.         END(HTML_H1);
  660.         
  661.     }
  662.     /* If we have seen a source file for this database, use that:
  663.     */
  664.  
  665. #ifdef CACHE_FILE_PREFIX
  666.     sprintf(filename, "%sWSRC-%s:%s:%.100s.txt",
  667.         CACHE_FILE_PREFIX,
  668.         server_name, service, www_database);
  669.  
  670.     fp = fopen(filename, "r");    /* Have we found this already? */
  671.     if (TRACE) fprintf(stderr,
  672.         "HTWAIS: Description of server %s %s.\n",
  673.         filename,
  674.         fp ? "exists already" : "does NOT exist!");
  675.  
  676.     if (fp) {
  677.         char c;
  678.         START(HTML_PRE);        /* Preformatted description */
  679.         while((c=getc(fp))!=EOF) PUTC(c);    /* Transfer file */
  680.         END(HTML_PRE);
  681.         fclose(fp);
  682.     }
  683. #endif
  684.     START(HTML_P);
  685.     PUTS("Specify search words.");
  686.     
  687.     FREE_TARGET;
  688.     
  689.     } else if (key) {                    /* S E A R C H */
  690.     char *p;
  691.     HTStructured * target;
  692.     
  693.     strncpy(keywords, key, MAX_KEYWORDS_LENGTH);
  694.     while(p=strchr(keywords, '+')) *p = ' ';
  695.     
  696.         /* Send advance title to get something fast to the other end */
  697.     
  698.     target = HTML_new(anAnchor, format_out, sink);
  699.     
  700.     START(HTML_ISINDEX);
  701.     START(HTML_TITLE);
  702.     PUTS(keywords);
  703.     PUTS(" (in ");
  704.     PUTS(wais_database);
  705.     PUTS(")");
  706.     END(HTML_TITLE);
  707.     
  708.     START(HTML_H1);
  709.     PUTS(keywords);
  710.     END(HTML_H1);
  711.  
  712.     request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */
  713.     if (TRACE) fprintf(stderr, "HTWAIS: Search for `%s' in `%s'\n",
  714.         keywords, wais_database);
  715.     if(NULL ==
  716.     generate_search_apdu(request_message + HEADER_LENGTH, 
  717.                 &request_buffer_length, 
  718.                 keywords, wais_database, NULL, MAXDOCS))
  719.     panic("request too large");
  720.     
  721.  
  722.     if(!interpret_message(request_message, 
  723.                 MAX_MESSAGE_LEN - request_buffer_length, 
  724.                 response_message,
  725.                 MAX_MESSAGE_LEN,
  726.                 connection,
  727.                 false    /* true verbose */
  728.                 )) {
  729.         panic("returned message too large");
  730.     
  731.         } else {    /* returned message ok */
  732.     
  733.         SearchResponseAPDU  *query_response = 0;
  734.         readSearchResponseAPDU(&query_response,
  735.             response_message + HEADER_LENGTH);
  736.         display_search_response(target, 
  737.             query_response, wais_database, keywords);
  738.         if (query_response->DatabaseDiagnosticRecords)
  739.         freeWAISSearchResponse(
  740.             query_response->DatabaseDiagnosticRecords);         
  741.         freeSearchResponseAPDU( query_response);
  742.     }    /* returned message not too large */
  743.     
  744.     FREE_TARGET;
  745.  
  746.     } else {            /* D O C U M E N T    F E T C H */
  747.     
  748.     HTFormat format_in;
  749.     boolean binary;     /* how to transfer stuff coming over */
  750.     HTStream * target;
  751.     long count;
  752.     any   doc_chunk;
  753.     any * docid = &doc_chunk;
  754.     if (TRACE) printf(
  755.         "HTWAIS: Retrieve document id `%s' type `%s' length %ld\n",
  756.         docname, doctype, document_length);
  757.         
  758.     format_in = 
  759.       !strcmp(doctype, "WSRC") ? HTAtom_for("application/x-wais-source") :
  760.       !strcmp(doctype, "TEXT") ? HTAtom_for("text/plain") :
  761.       !strcmp(doctype, "HTML") ? HTAtom_for("text/html") :
  762.       !strcmp(doctype, "GIF")  ? HTAtom_for("image/gif") :
  763.                             HTAtom_for("application/octet-stream");
  764.     binary = 
  765.       0 != strcmp(doctype, "WSRC") &&
  766.       0 != strcmp(doctype, "TEXT") &&
  767.       0 != strcmp(doctype, "HTML") ;
  768.  
  769.  
  770.     target = HTStreamStack(format_in, format_out, sink, anAnchor);
  771.     if (!target) return HTLoadError(sink, 500,
  772.         "Can't convert format of WAIS document");
  773. /*    Decode hex or litteral format for document ID
  774. */    
  775.     WAIS_from_WWW(docid, docname);
  776.  
  777.     
  778. /*    Loop over slices of the document
  779. */    
  780.     for(count = 0; 
  781.         count * CHARS_PER_PAGE < document_length;
  782.         count++){
  783.       char *type = s_strdup(doctype);    /* Gets freed I guess */
  784.       request_buffer_length = MAX_MESSAGE_LEN; /* Amount left */
  785.       if (TRACE) fprintf(stderr, "HTWAIS: Slice number %ld\n", count);
  786.       if(0 ==
  787.           generate_retrieval_apdu(request_message + HEADER_LENGTH,
  788.             &request_buffer_length, 
  789.             docid, 
  790.             CT_byte,
  791.             count * CHARS_PER_PAGE,
  792.             MIN((count + 1) * CHARS_PER_PAGE,document_length),
  793.             type,
  794.             wais_database
  795.             ))
  796.         panic("request too long");
  797.       
  798.       /*    Actually do the transaction given by request_message */   
  799.       if(0 ==
  800.          interpret_message(request_message, 
  801.                    MAX_MESSAGE_LEN - request_buffer_length, 
  802.                    response_message,
  803.                    MAX_MESSAGE_LEN,
  804.                    connection,
  805.                    false /* true verbose */    
  806.                    ))
  807.         panic("Returned message too large");
  808.  
  809.       /*     Parse the result which came back into memory.
  810.       */
  811.       readSearchResponseAPDU(&retrieval_response, 
  812.                  response_message + HEADER_LENGTH);
  813.  
  814.       if(NULL == ((WAISSearchResponse *)
  815.           retrieval_response->DatabaseDiagnosticRecords)->Text){
  816.         /* display_search_response(target, retrieval_response,
  817.                     wais_database, keywords); */
  818.         PUTS("No text was returned!\n");
  819.         /* panic("No text was returned"); */
  820.       } else {
  821.       
  822.         output_text_record(target,
  823.            ((WAISSearchResponse *)
  824.             retrieval_response->DatabaseDiagnosticRecords)->Text[0],
  825.         false, binary);
  826.       
  827.       } /* If text existed */
  828.       
  829.     }    /* Loop over slices */
  830.  
  831.     (*target->isa->free)(target);
  832.  
  833.     free (docid->bytes);
  834.     
  835.     freeWAISSearchResponse( retrieval_response->DatabaseDiagnosticRecords); 
  836.     freeSearchResponseAPDU( retrieval_response);
  837.  
  838.     } /* If document rather than search */
  839.  
  840.  
  841.  
  842.  
  843. /*    (This postponed until later,  after a timeout:)
  844. */
  845.     if (connection) close_connection(connection);
  846.     if (wais_database) free(wais_database);
  847.     s_free(request_message);
  848.     s_free(response_message);
  849.  
  850.     free(names);
  851.     return HT_LOADED;
  852. }
  853.  
  854. GLOBALDEF PUBLIC HTProtocol HTWAIS = { "wais", HTLoadWAIS, NULL };
  855.  
  856.  
  857.